package com.wisezone.workflow.core.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.wisezone.common.Pagination;
import com.wisezone.workflow.bean.WfActivity;
import com.wisezone.workflow.bean.WfActivityInstance;
import com.wisezone.workflow.bean.WfLink;
import com.wisezone.workflow.bean.WfProcessDefinition;
import com.wisezone.workflow.bean.WfProcessInstance;
import com.wisezone.workflow.bean.WfVariable;
import com.wisezone.workflow.bean.form.WorkFlowForm;
import com.wisezone.workflow.bean.po.NodeModule;
import com.wisezone.workflow.bean.po.PositionModule;
import com.wisezone.workflow.bean.po.ProcessModule;
import com.wisezone.workflow.bean.po.TransitionModule;
import com.wisezone.workflow.bean.po.VariableModule;
import com.wisezone.workflow.bean.search.WfProcessDefinitionSearch;
import com.wisezone.workflow.bean.search.WfProcessInstanceSearch;
import com.wisezone.workflow.bean.search.WorkFlowSearch;
import com.wisezone.workflow.core.Activity;
import com.wisezone.workflow.core.ActivityInstance;
import com.wisezone.workflow.core.BaseProperty;
import com.wisezone.workflow.core.FlowEngine;
import com.wisezone.workflow.core.ProcessDefinition;
import com.wisezone.workflow.core.ProcessInstance;
import com.wisezone.workflow.exception.WfCoreException;
import com.wisezone.workflow.utils.ProcessUtils;

/**
 * 流程引擎类
 * @author tss 2009-09-05
 *
 */
public class FlowEngineImpl extends BasePropertyImpl implements FlowEngine{

	/**
	 * 构造方法
	 */
	public FlowEngineImpl() {
	}
	
	/**
	 * 流程模板加载（根据标识）
	 * @param name
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessDefinition loadProcessDefByKey(String key) throws WfCoreException{
		
		try {	
			if(StringUtils.isEmpty(key)){
				throw new IllegalArgumentException("流程模板标识不能为空");
			}
			WfProcessDefinitionSearch searchEntity = new WfProcessDefinitionSearch();
			Integer maxVer = this.getWfProcessDefinitionDao().getMaxVer(key);
			searchEntity.setKey(key);
			searchEntity.setVersion(maxVer);
			return getProcessDefinition(searchEntity);
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}		
	}
	
	
	/**
	 * 流程模板加载（根据ID）
	 * @param id
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessDefinition loadProcessDefById(Long id) throws WfCoreException{
		
		try {	
			if(id == null){
				throw new IllegalArgumentException("流程模板ID不能为空");
			}
			WfProcessDefinitionSearch searchEntity = new WfProcessDefinitionSearch();
			searchEntity.setId(id);
			return getProcessDefinition(searchEntity);
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}		
	}
	
	
	/**
	 * 根据ID加载活动
	 * @param id 活动Id
	 * @return
	 * @throws WfCoreException
	 */
	public Activity loadActivity(Long id) throws WfCoreException{
		
		try {

			WfActivity wfActivity = this.getWfActivityDao().load(id);
		    WfProcessDefinition wfProcess = this.getWfProcessDefinitionDao().load(wfActivity.getProcessDefId());
			ProcessDefinition processDefinition = this.loadProcessDefById(wfProcess.getId());
			return processDefinition.loadActivityById(id);
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}		
	}
	
	/**
	 * 根据ID 加载活动实例
	 * @param id
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance loadActivityInstance(Long id) throws WfCoreException{
		
		try {
			
			WfActivityInstance wfActivityinstance = getWfActivityInstanceDao().load(id);
			
			if(wfActivityinstance == null) return null;
			WfProcessInstance wfProcessinstance = getWfProcessInstanceDao().load(wfActivityinstance.getProcessInstId());
				
			if(wfProcessinstance == null) return null;
			ProcessDefinition processDefinition = loadProcessDefById(wfProcessinstance.getProcessDefId());
			
			return processDefinition.loadActivityInstance(id);
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}
	

    /**
	 * 当前流程实例相关表单信息查询(分页)
	 * @param hql
	 * @param searchEntity
	 * @return
	 * @throws Exception
	 */
	public<T> Pagination<T> listProcessInstByPage(WorkFlowSearch searchEntity) throws WfCoreException{
		
		return this.getWfProcessInstanceDao().listFormByPage(searchEntity);
	}
	
	
	
	/**
	 * 获得流程模板
	 * @param wfProcess
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessDefinition getProcessDefinition(WfProcessDefinitionSearch searchEntity) throws WfCoreException{
		
		if(searchEntity == null){
			throw new IllegalArgumentException("流程模板查询对象不能为空");
		}
		try {
			
			WfProcessDefinition wfProcess = (WfProcessDefinition) getWfProcessDefinitionDao().get(searchEntity);
			
			//构造processDefinition 对象
			ProcessDefinition processDefinition = new ProcessDefinitionImpl(wfProcess,this);
			
			return processDefinition;
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}		
	}
	
	/**
	 * 获得流程模版列表
	 * @param searchEntity
	 * @return
	 * @throws WfCoreException
	 */
	public List<ProcessDefinition> listProcessDefinition(WfProcessDefinitionSearch searchEntity) throws WfCoreException {
		
		if(searchEntity == null){
			throw new IllegalArgumentException("流程模板查询对象不能为空");
		}
		List<ProcessDefinition> list = new ArrayList<ProcessDefinition>();
		searchEntity = new WfProcessDefinitionSearch();
		List<WfProcessDefinition> processList = this.getWfProcessDefinitionDao().listAll(searchEntity);
		for(Iterator<WfProcessDefinition> it = processList.iterator(); it.hasNext();){
			ProcessDefinition entity = new ProcessDefinitionImpl(it.next(),this);
			list.add(entity);
		}
		return list;
		
	}
	
	
	/**
	 * 获得当前流程实例节点信息
	 * @param processInstId
	 * @return
	 * @throws WfCoreException
	 */
	public List<PositionModule> getPositions(Long processInstId) throws WfCoreException{
		
		if(processInstId == null){
			throw new IllegalArgumentException("流程实例Id 不能为空");
		}

		ProcessInstance processInst = this.loadProcessInstance(processInstId);
	    List<ActivityInstance> activityInstList = processInst.getNotStartActivityInstList();
	    if(activityInstList == null || activityInstList.size() == 0){
	    	return null;
	    }

    	List<PositionModule> positionList = new ArrayList<PositionModule>();
    	for(Iterator<ActivityInstance> it = activityInstList.iterator(); it.hasNext();){
    		ActivityInstance activityInst = it.next();
    		PositionModule positionModule = new PositionModule();
    		String pos = activityInst.getActivity().getModel().getPosition();
    		if(StringUtils.isEmpty(pos)){
    			continue;
    		}
    		String posStr [] = pos.split(":");
    		if(posStr == null || posStr.length < 2){
    			continue;
    		}
    		String [] xyStr = posStr[1].split(",");
    		if(xyStr == null || xyStr.length < 2){
    			continue;
    		}
    		String x = xyStr[0];
    		String y = xyStr[1];
    		String [] whStr = posStr[0].split(",");
    		if(whStr == null || whStr.length < 2){
    			continue;
    		}
    		String width = whStr[0];
    		String height = whStr[1];
    		
    		positionModule.setX(x);
    		positionModule.setY(y);
    		positionModule.setWidth(width);
    		positionModule.setHeight(height);
    		positionList.add(positionModule);
    	}
    	return positionList;
    
	
	}
	
	/**
	 * 根据流程实例ID 加载流程实例
	 * @param id
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance loadProcessInstance(Long id) throws WfCoreException{
		
		if(id == null){
			throw new IllegalArgumentException("流程实例ID不能为空");
		}
		ProcessInstance processInstance = null;
		try {		
			
			WfProcessInstance wfProcessinstance = getWfProcessInstanceDao().load(id);
		    WfProcessDefinition wfProcess = getWfProcessDefinitionDao().load(wfProcessinstance.getProcessDefId());
		    ProcessDefinition processDefinition = this.loadProcessDefById(wfProcess.getId());
		    processInstance = processDefinition.loadProcessInstById(id);
		    
			
		} catch (WfCoreException e) {
		}	
		return processInstance;
	}
	
	/**
	 * 发起一个流程实例
	 * @param key
	 * @param variableMap
	 * @param starter
	 * @throws WfCoreException
	 */
	public ProcessInstance startProcessInstByKey(String key,String porcessInstName,Map<String, Object> variableMap,Long starter) throws WfCoreException{
		
		if(starter == null){
			throw new IllegalArgumentException("流程发起人不能为空");
		}
		try {
			
			ProcessDefinition processDefinition = loadProcessDefByKey(key);
			
			ProcessInstance processInstance = processDefinition.createProcessInstance();
			
			//设置属性
			processInstance.setName(porcessInstName);
			
			processInstance.start(variableMap); //流程发起
			
			processInstance.setStarter(starter); // 设置参与者
			
			this.submit(processInstance); //提交数据   
			
			return processInstance;
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new WfCoreException(e);
		}
		
	}
	
	
	
	/**
	 * 发起流程并完成开始活动
	 * @param searchEntity
	 * @return workflowForm
	 * @throws WfCoreException
	 */
	public WorkFlowForm complateStartActivity(WorkFlowSearch searchEntity) throws WfCoreException{

		if(searchEntity == null){
			throw new IllegalArgumentException("工作流参数对象不能为空");
		}
		Long startUserId = searchEntity.getActorId();
		Map<String,Object> variableMap = searchEntity.getVariableMap();
		Map<String,Object> localVariableMap = searchEntity.getLocalVariableMap();
		Long [] userIds = searchEntity.getUserIds();
		Long [] userGroupIds = searchEntity.getUserGroupIds();
		String opinion = searchEntity.getOpinion();
		
		String processInstName = searchEntity.getName();
		
		ProcessInstance processInstance = startProcessInstByKey(searchEntity.getKey(),processInstName, variableMap, startUserId);
		
		ActivityInstance activityInstance = processInstance
				.startActivityInstance(); //创建一个开始活动
		
		activityInstance.start(localVariableMap); //活动开始
		
		activityInstance.setActor(startUserId); //设置活动参与者
		
		activityInstance.setOpinion(opinion);  //设置活动意见
		
		
		ActivityInstance currentActivityInst =  null;
		
		if(userIds == null && userGroupIds == null){
			
			// 结束
			Map<String,Object> variables = new HashMap<String,Object>();
			if(searchEntity.getLinkId() != null){
				variables.put(NEXT_LINK_ID, searchEntity.getLinkId());
			}
			currentActivityInst = activityInstance.end(variables);
		}else{
			currentActivityInst = activityInstance.end(userIds,userGroupIds);    //转到下一活动结束
		}
		
		
		this.submit(activityInstance); //提交数据   
		
		WorkFlowForm workflowForm = new WorkFlowForm();
		workflowForm.setProcessInstId(processInstance.getModel().getId());
	    
		//获得流程状态ID
	    Object status =  currentActivityInst.getStatus();
	    String statusId =  status != null ? status.toString() : null;
	    workflowForm.setStatusId(statusId);
	    
	    return workflowForm;
	    
	}
	
	
	/**
	 * 活动操作
	 * @param searchEntity
	 * @return  workflowForm
	 * @throws WfCoreException
	 */
	public WorkFlowForm operateActivity(WorkFlowSearch searchEntity) throws WfCoreException{
		
		
		if(searchEntity == null){
			throw new IllegalArgumentException("工作流参数对象不能为空");
		}
		//Map<String,Object> variableMap = searchEntity.getVariableMap();  //待实现
		Map<String,Object> localVariableMap = searchEntity.getLocalVariableMap();
		
		// 获得任务实例
		ActivityInstance ai = this
				.loadActivityInstance(searchEntity.getActivityInstId());

		if(ai.getActivity().getModel().getCategory().equals(this.getActivityCategory(BaseProperty.ACTIVITY_EMAIL))){  //邮件活动  各自业务
			ai.getProcessInstance().setVariable("content", searchEntity.getOpinion());
		}
		// 开始
		ai.start(localVariableMap);
		
		// 设置参与者
		ai.setActor(searchEntity.getActorId());

		// 设置活动意见
		ai.setOpinion(searchEntity.getOpinion());

		// 结束
		Map<String,Object> variables = new HashMap<String,Object>();
		if(searchEntity.getLinkId() != null){
			variables.put(NEXT_LINK_ID, searchEntity.getLinkId());
		}
		if(searchEntity.getUserIds() != null && searchEntity.getUserIds().length > 0){
			variables.put(ACTOR_IDS, searchEntity.getUserIds());
		}
		if(searchEntity.getUserGroupIds() != null && searchEntity.getUserGroupIds().length > 0){
			variables.put(ACTOR_GROUP_IDS, searchEntity.getUserGroupIds());
		}
		
		ActivityInstance curentActivityInst = ai.end(variables);
		

		// 提交数据
		this.submit(ai);
		
		Object status = null;
		String variableName = BaseProperty.STATE_CREATE;
		if(ai.getProcessInstance().isEnd()){
			variableName = BaseProperty.STATE_END;
		}
		status = curentActivityInst.getVariable(variableName);
		WorkFlowForm workflowForm = new WorkFlowForm();
		if(status != null){
			workflowForm.setStatusId(status.toString());
		}
		
		return workflowForm;
	}

	


	/**
	 * 保存流程模板
	 * 
	 * @param jsonStr
	 * @throws WfCoreException
	 */
	public void save(WfProcessDefinition entity) throws WfCoreException {

		if(entity == null){
			throw new IllegalArgumentException("流程模板不能为空");
		}
		ProcessModule processModule = null;
		String fileContent = entity.getFileContent();
		try {
			processModule = ProcessUtils.jsonToProcess(fileContent);
		} catch (Exception e) {
			throw new WfCoreException("模板 json 数据 转 Module 失败", e);
		}
		entity.setName(processModule.getName());
		entity.setKey(processModule.getKey());
		entity.setVersion(Integer.valueOf(processModule.getVersion()));
		entity.setFileContent(fileContent);
		try {
			this.getWfProcessDefinitionDao().save(entity);
		} catch (Exception e) {
			throw new WfCoreException("模板保存失败", e);
		}
	}

	/**
	 * 修改流程模板
	 * @param jsonStr
	 * @throws WfCoreException
	 */
	public void update(Long id,String jsonStr) throws WfCoreException{
		
		ProcessModule processModule = ProcessUtils.jsonToProcess(jsonStr);
		WfProcessDefinition wfProcess = this.loadProcessDefById(id).getModel();
		wfProcess.setKey(processModule.getKey());
		wfProcess.setName(processModule.getName());
		wfProcess.setVersion(Integer.valueOf(processModule.getVersion()));
		wfProcess.setFileContent(jsonStr);
		wfProcess.setDescription(processModule.getDescription());
		this.getWfProcessDefinitionDao().update(wfProcess);
	}
	
	/**
	 * 流程发布(覆盖)
	 * @param filePath
	 * @throws WfCoreException
	 */
	public void publish(Long id) throws WfCoreException{
		
		
		ProcessDefinition processDefinition = this.loadProcessDefById(id);
		WfProcessDefinition wfProcess = processDefinition.getModel();
		String jsonStr = wfProcess.getFileContent();
		ProcessModule processModule = ProcessUtils.jsonToProcess(jsonStr);
		Map<String,WfActivity> activityMap = new HashMap<String,WfActivity>();
		
		//先删除，再保存
		if(id != null){
			
			this.getWfActivityDao().deleteByProcessDefId(id);
			this.getWfLinkDao().deleteByProcessDefId(id);
			this.getWfVariableDao().deleteByProcessDefId(id);
		}
		
		//流程变量保存
		log.info("流程变量保存开始");
		List<VariableModule> variableModuleList = processModule.getVariableModules();
		if(variableModuleList != null && variableModuleList.size() > 0){
			for(Iterator<VariableModule> it = variableModuleList.iterator(); it.hasNext();){
				
				VariableModule variableModule = it.next();
				WfVariable wfVariable = new WfVariable();
				wfVariable.setProcessDefId(wfProcess.getId());
				wfVariable.setName(variableModule.getName());
				wfVariable.setValue(variableModule.getValue());
				this.getWfVariableDao().save(wfVariable);
			}
		}
		
		//保存活动
		log.info("活动保存开始");
		List<NodeModule> taskModuleList = processModule.getNodeModules();
		for(int i = 0; i < taskModuleList.size(); i++){
			NodeModule taskModule = taskModuleList.get(i);
			WfActivity wfActivity = new WfActivity();
			wfActivity.setName(taskModule.getName());
			String category = taskModule.getCategory();
			if(StringUtils.isNotEmpty(category)){
				Long activityCateogryId = getActivityCategory(category);
				wfActivity.setCategory(activityCateogryId);
			}
			String taskCategory = taskModule.getTaskCategory();
			if(StringUtils.isNotEmpty(taskCategory)){
				Long taskCategoryId = getTaskCategory(taskCategory);
				wfActivity.setTaskCategory(taskCategoryId);
			}
            wfActivity.setPosition(taskModule.getPosition());
			wfActivity.setOrderBy(i);
			wfActivity.setProcessDefId(wfProcess.getId());
			this.getWfActivityDao().save(wfActivity);
			activityMap.put(wfActivity.getName(), wfActivity);
		}
		

		for(int i = 0; i < taskModuleList.size(); i++){
			
			NodeModule taskModule = taskModuleList.get(i);
			
			//保存链接
			log.info("链接保存开始");
			List<TransitionModule> transitionModuleList = taskModule.getTransitionModules();
			for(Iterator<TransitionModule> it = transitionModuleList.iterator(); it.hasNext();){
				
				TransitionModule transitionModule = it.next();
				WfLink wfLink = new WfLink();
				wfLink.setPosition(transitionModule.getPosition());
				wfLink.setCondition(transitionModule.getCondition());
				wfLink.setName(transitionModule.getName());
				wfLink.setProcessDefId(wfProcess.getId());
				Long preAvtivityId = activityMap.get(transitionModule.getFrom()).getId();
				Long aid = activityMap.get(transitionModule.getTo()).getId();
				wfLink.setPreActivityId(preAvtivityId);
				wfLink.setActivityId(aid);
				this.getWfLinkDao().save(wfLink);
			}
			
			//流程节点变量保存
			log.info("流程节点变量保存开始");
			variableModuleList = taskModule.getVariableModules();
			if(variableModuleList != null && variableModuleList.size() > 0){
				for(Iterator<VariableModule> it = variableModuleList.iterator(); it.hasNext();){
					
					VariableModule variableModule = it.next();
					WfVariable wfVariable = new WfVariable();
					wfVariable.setProcessDefId(wfProcess.getId());
					Long activityId = activityMap.get(taskModule.getName()).getId();
					wfVariable.setActivityId(activityId);
					wfVariable.setName(variableModule.getName());
					wfVariable.setValue(variableModule.getValue());
					this.getWfVariableDao().save(wfVariable);
				}
			}
		}
	}
	
	
    
    
	/**
	 * 数据提交（流程实例）
	 * @param pi
	 * @throws WfCoreException
	 */
	public void submit(ProcessInstance pi) throws WfCoreException{
		
		if(pi != null && pi.getModel() != null){
			
			pi.update(pi.getModel());
		}
	}
	
	/**
	 * 数据提交（活动实例）
	 * @param ai
	 * @throws WfCoreException
	 */
	public void submit(ActivityInstance ai) throws WfCoreException{
		
        if(ai != null && ai.getModel() != null){
			
        	ai.update(ai.getModel());
		}
        ProcessInstance pi = ai.getProcessInstance();
        submit(pi);
        
	}

	
}
